package com.wedimob.slideshare.task.disk;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URI;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.wedimob.slideshare.Writer;

public class DefaultWriter implements Writer {

    public static URI getParent(URI uri) {
        try {
            String elemts[] = uri.toString().split("/");
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < elemts.length - 1; i++) {
                if (i > 0)
                    sb.append("/");
                sb.append(elemts[i]);
            }
            return new URI(sb.toString());
        } catch (Exception e) {
            System.err.println(uri);
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static void createDirIfNecessary(URI uri) {
        try {
            System.err.println("createDirIfNecessary : " + uri);
            File filedir = new File(getParent(uri).getPath());
            if (!filedir.exists()) {
                int nbAttemp = 0;
                boolean isSuccess = false;
                do {
                    if (nbAttemp > 0)
                        Thread.sleep(20);

                    isSuccess = filedir.mkdirs();
                } while (!isSuccess && nbAttemp < 3);

                if (!isSuccess)
                    throw new Exception("Cannot create " + filedir);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void write(byte[] data, URI uri) {
        try {
            createDirIfNecessary(uri);
            FileOutputStream out = new FileOutputStream(new File(uri));
            out.write(data);
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void zip(URI src, URI dest) {
        try {
            createDirIfNecessary(dest);
            ZipOutputStream zos = new
                    ZipOutputStream(new FileOutputStream(dest.getPath()));
            zipDir(src.getPath(), zos);
            zos.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void zipDir(String dir2zip, ZipOutputStream zos)
    {
        try
        {
            File zipDir = new File(dir2zip);
            String[] dirList = zipDir.list();
            byte[] readBuffer = new byte[2156];
            int bytesIn = 0;
            for (int i = 0; i < dirList.length; i++)
            {
                File f = new File(zipDir, dirList[i]);
                if (f.isDirectory())
                {
                    String filePath = f.getPath();
                    zipDir(filePath, zos);
                    continue;
                }

                FileInputStream fis = new FileInputStream(f);
                ZipEntry anEntry = new ZipEntry(f.getName());
                zos.putNextEntry(anEntry);
                while ((bytesIn = fis.read(readBuffer)) != -1)
                    zos.write(readBuffer, 0, bytesIn);
                fis.close();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delete(URI dir) {
        try
        {
            File f = new File(dir);
            if (f.isDirectory()) {
                for (File c : f.listFiles())
                    delete(c.toURI());
            }
            if (!f.delete())
                System.err.println("Failed to delete file: " + f);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteEmpty(URI dir) {
        try
        {
            File f = new File(dir);
            if (f.isDirectory()) {
                for (File c : f.listFiles())
                    deleteEmpty(c.toURI());

                if (f.listFiles().length == 0) {
                    f.delete();
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void move(URI src, URI dest) {
        try
        {
            File from = new File(src);

            if (!from.exists() || !from.isDirectory()) {
                throw new RuntimeException("Directory does not exist: " + src);
            }
            
            createDirIfNecessary(dest);
            File to = new File(dest);            

            // Rename
            int nbAttemp = 0;
            boolean isSuccess = false;
            do {
                if (nbAttemp > 0)
                    Thread.sleep(20);

                isSuccess = from.renameTo(to);
            } while (!isSuccess && nbAttemp < 3);

            if (!isSuccess)
                throw new Exception("Cannot move " + src + " to " + dest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
